//*****************************************************************************
//
// startup_ewarm.c - Boot code for IAR tools for Stellaris.
//
// Copyright (c) 2006-2007 Luminary Micro, Inc.  All rights reserved.
//
// Software License Agreement
//
// Luminary Micro, Inc. (LMI) is supplying this software for use solely and
// exclusively on LMI's microcontroller products.
//
// The software is owned by LMI and/or its suppliers, and is protected under
// applicable copyright laws.  All rights are reserved.  Any use in violation
// of the foregoing restrictions may subject the user to criminal sanctions
// under applicable laws, as well as to civil liability for the breach of the
// terms and conditions of this license.
//
// THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 323 of the Stellaris boot loader.
//
//*****************************************************************************

#include "../../hw_memmap.h"
#include "boot_loader.h"

//*****************************************************************************
//
// Enable the IAR extensions for this source file.
//
//*****************************************************************************
#pragma language=extended

//*****************************************************************************
//
// Forward declaration of the default fault handlers.
//
//*****************************************************************************
void ResetISR(void);
static void IntDefaultHandler(void);

//*****************************************************************************
//
// The entry point for the application.
//
//*****************************************************************************
extern int main(void);

//*****************************************************************************
//
//! A union that describes the entries of the vector table.  The union is
//! needed since the first entry is the stack pointer and the remainder are
//! function pointers.
//
//*****************************************************************************
typedef union
{
    void (*pfnHandler)(void);
    unsigned long ulPtr;
}
uVectorEntry;

//*****************************************************************************
//
//! The minimal vector table for a Cortex M3.  Note that the proper constructs
//! must be placed on this to ensure that it ends up at physical address
//! 0x00000000.  If the auto-baud feature is used then the vector table must
//! grow to encompass the GPIO interrupt A which is used by the auto-baud
//! algorithm.
//
//*****************************************************************************
__root const uVectorEntry g_pfnVectors[] @ "INTVEC" =
{
                                            // The initial stack pointer
    { .ulPtr = (unsigned long)pulStack + sizeof(pulStack) },
                                            // The reset handler
    { .ulPtr = (unsigned long)ResetISR - SRAM_BASE },
    IntDefaultHandler,                      // The NMI handler
    IntDefaultHandler,                      // The hard fault handler
    IntDefaultHandler,                      // The MPU fault handler
    IntDefaultHandler,                      // The bus fault handler
    IntDefaultHandler,                      // The usage fault handler
#ifdef AUTOBAUD
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // SVCall handler
    IntDefaultHandler,                      // Debug monitor handler
    0,                                      // Reserved
    IntDefaultHandler,                      // The PendSV handler
    IntDefaultHandler,                      // The SysTick handler
    IntDefaultHandler,                      // GPIO Port A
#endif
};

//*****************************************************************************
//
// The following are constructs created by the linker, indicating where the
// the "data" and "bss" segments reside in memory.  The initializers for the
// for the "data" segment resides immediately following the "text" segment.
//
//*****************************************************************************
#pragma segment="DATA_Z"
#pragma segment="DATA_C"


//*****************************************************************************
//
//! This is a typedef used to call the main routine.
//
//*****************************************************************************
typedef void (*tpVoid(void));

//*****************************************************************************
//
//! This function handles setting up the boot loader for operation from SRAM.
//!
//! This is the code that gets called when the processor first starts execution
//! following a reset event.  This function copies all of the code from flash
//! to SRAM so that the boot loader itself can be updated in the flash.  This
//! function also takes care of zeroing out the bss section befor calling the
//! main() function which will be run from SRAM.
//!
//! \return This function shoud never be returned to.
//
//*****************************************************************************
void
ResetISR(void)
{
    unsigned long *pulSrc, *pulDest, *pulEnd;
    tpVoid *pfMain;

    //
    // Copy the code and constant data segment initializers from flash to SRAM.
    //
    pulSrc = 0;
    pulDest = (unsigned long *)SRAM_BASE;
    pulEnd = __segment_end("DATA_C");
    while(pulDest < pulEnd)
    {
        *pulDest++ = *pulSrc++;
    }

    //
    // Zero fill the bss segment.
    //
    pulDest = __segment_begin("DATA_Z");
    pulEnd = __segment_end("DATA_Z");
    while(pulDest < pulEnd)
    {
        *pulDest++ = 0;
    }

    //
    // Call the application's entry point. Without this change the compiler
    // will do an branch with offset which causes it to execute from flash
    // and not from SRAM.
    //
    pfMain = (tpVoid *)((unsigned long)main);
    pfMain();
}

//*****************************************************************************
//
//! The default handler for any unhandled interrupt.
//!
//! This is the code that gets called when the processor receives an unexpected
//! interrupt.  This simply enters an infinite loop, preserving the system
//! state for examination by a debugger.
//!
//! \return This function never returns.
//
//*****************************************************************************
static void
IntDefaultHandler(void)
{
    //
    // Go into an infinite loop.
    //
    while(1)
    {
    }
}

//*****************************************************************************
//
//! Calls the application at ulBaseAddress.
//!
//! This function reads the stack pointer from the base address passed in and
//! also moves the vector table to point to the vector table provided by the
//! application.  Once the vector table and stack are configured this function
//! reads out the start address for the application and branches to it.
//!
//! \param ulBaseAddress is the base address in flash of the application to
//!     run. This should point to a valid interrupt vector table.
//!
//! \return This function never returns.
//
//*****************************************************************************
void
CallApplication(unsigned long ulBaseAddress)
{
    __asm(
    "mov r1, #0xE0000000\n"
    "add r1, r1, #0x0000ED00\n"
    "str r0, [r1,#8]\n"
    "ldr sp, [r0], #4\n"
    "ldr r0, [r0]\n"
    "bx  r0\n");
}

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif
